package com.me.test.config;

import com.me.test.enums.ErrorCodeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

/**
 * 全局的统一异常处理，
 *
 * @author ME
 */
@RestControllerAdvice(annotations = RestController.class)
public class GlobalExceptionHandlerAdvice {

    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandlerAdvice.class);

    /**
     * 校验 @RequestBody 提交的 json、xml 时的错误，@Valid、@Validated
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Wrapper<?> handleError(MethodArgumentNotValidException notValidException) {
        BindingResult bindingResult = notValidException.getBindingResult();
        if (bindingResult.hasErrors()) {
            FieldError fieldError = (FieldError) bindingResult.getAllErrors().get(0);
            String message = "RequestBody 参数校验异常：[" + fieldError.getField() + "] " + fieldError.getDefaultMessage();
            log.error(message);
            return Wrapper.error(ErrorCodeEnum.A0001, message);
        }

        return Wrapper.error(ErrorCodeEnum.A0001);
    }

    /**
     * 校验 url请求参数、form表单 时的错误，@Valid、@Validated
     */
    @ExceptionHandler(BindException.class)
    public Wrapper<?> handleError(BindException notValidException) {
        BindingResult bindingResult = notValidException.getBindingResult();
        if (bindingResult.hasErrors()) {
            FieldError fieldError = (FieldError) bindingResult.getAllErrors().get(0);
            String message = "Param 参数校验异常：[" + fieldError.getField() + "] " + fieldError.getDefaultMessage();
            log.error(message);
            return Wrapper.error(ErrorCodeEnum.A0001, message);
        }

        return Wrapper.error(ErrorCodeEnum.A0001);
    }

    /**
     * Hibernate 校验时的错误
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Wrapper<?> handleError(ConstraintViolationException notValidException) {
        Set<ConstraintViolation<?>> violations = notValidException.getConstraintViolations();
        if (violations.size() > 0) {
            ConstraintViolation<?> next = violations.iterator().next();
            log.error("Hibernate 校验参数异常：{}", next.getMessage());
            return Wrapper.error(ErrorCodeEnum.A0001, next.getMessage());
        }

        return Wrapper.error(ErrorCodeEnum.A0001);
    }

    /**
     * 消息不能读取
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Wrapper<?> handleError(HttpMessageNotReadableException e) {
        log.error("Controller异常信息：", e);
        return Wrapper.error(ErrorCodeEnum.B0001.getCode(), e.getMessage());
    }

    /**
     * 不支持当前请求方法
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public Wrapper<?> handleError(HttpRequestMethodNotSupportedException e) {
        log.error("Controller异常信息：", e);
        return Wrapper.error(ErrorCodeEnum.B0001.getCode(), e.getMessage());
    }

    /**
     * 不支持当前媒体类型
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
    public Wrapper<?> handleError(HttpMediaTypeNotSupportedException e) {
        log.error("Controller异常信息：", e);
        return Wrapper.error(ErrorCodeEnum.B0001.getCode(), e.getMessage());
    }

    @ExceptionHandler(value = BusinessException.class)
    public Wrapper<?> handleBusinessException(BusinessException e) {
        return Wrapper.error(e.getCode(), e.getMessage());
    }

    /**
     * RuntimeException 兜底方案
     */
    @ExceptionHandler(RuntimeException.class)
    public Wrapper<?> handleRuntimeException(RuntimeException e) {
        log.error("Controller异常信息：", e);
        return Wrapper.error(ErrorCodeEnum.B0001.getCode(), e.getMessage());
    }

    /**
     * 其余检测异常 兜底
     */
    @ExceptionHandler(Exception.class)
    public Wrapper<?> handleException(Exception e) {
        log.error("Controller异常信息：", e);
        return Wrapper.error(ErrorCodeEnum.B0001.getCode(), e.getMessage());
    }

}
